#ifndef GAME_H
#define GAME_H

#include <vector>
#include <string>
#include <memory>
#include <mutex>
#include <random>

enum class Direction { UP, DOWN, LEFT, RIGHT };
enum class GameStatus { OK, KILL_BY_WALL, KILL_BY_SELF, END_NORMAL };

struct Position {
    int x;
    int y;
    bool operator==(const Position& other) const {
        return x == other.x && y == other.y;
    }
};

class Snake {
public:
    Snake(int id, const Position& startPos, int color);
    
    void changeDirection(Direction newDir);
    void move();
    bool checkCollision(const Position& pos) const;
    bool checkSelfCollision() const;
    bool checkWallCollision(int mapWidth, int mapHeight) const;
    void grow();
    
    int getId() const { return id_; }
    const std::vector<Position>& getBody() const { return body_; }
    Direction getDirection() const { return direction_; }
    GameStatus getStatus() const { return status_; }
    int getScore() const { return score_; }
    int getColor() const { return color_; }
    int getSpeed() const { return speed_; }
    
    void setStatus(GameStatus status) { status_ = status; }
    void increaseScore(int points) { score_ += points; }
    
private:
    int id_;
    std::vector<Position> body_;
    Direction direction_;
    GameStatus status_;
    int score_;
    int color_;
    int speed_;
};

class Food {
public:
    Food(int x, int y) : position_{x, y} {}
    const Position& getPosition() const { return position_; }
    
private:
    Position position_;
};

class Game {
public:
    Game(int width, int height);
    
    void addPlayer(int playerId);
    void removePlayer(int playerId);
    void changeDirection(int playerId, Direction dir);
    void update();
    std::string getGameState() const;
    
private:
    void generateFood();
    bool isPositionFree(const Position& pos) const;
    
    int width_;
    int height_;
    std::vector<std::unique_ptr<Snake>> snakes_;
    std::vector<Food> foods_;
    mutable std::mutex mutex_;
    std::random_device rd_;
    std::mt19937 gen_;
    std::uniform_int_distribution<> xDist_;
    std::uniform_int_distribution<> yDist_;
};

#endif // GAME_H